package com.codrim.cs.data.server.rpc;

import com.alibaba.dubbo.config.annotation.Service;
import com.codrim.cs.data.rpc.OfferDataService;
import com.codrim.cs.data.rpc.dto.param.BillCsOfferParam;
import com.codrim.cs.data.rpc.dto.param.OfferDataParamDTO;
import com.codrim.cs.data.rpc.dto.param.PageResult;
import com.codrim.cs.data.rpc.dto.param.StatementOfferDTO;
import com.codrim.cs.data.rpc.dto.result.OfferDataDTO;
import com.codrim.cs.data.server.dao.RealTimeDataDao;
import com.codrim.cs.data.server.dao.entity.OfferDataDO;
import com.codrim.cs.data.server.dao.mapper.StatCsAdvOfferMapper;
import com.codrim.cs.data.server.dao.param.OfferDataParam;
import com.codrim.cs.data.server.dao.param.RealTimeDataSearchParam;
import com.codrim.cs.data.server.dao.realtime.RealTimeData;
import com.codrim.cs.data.server.dao.realtime.RealTimeGroupByField;
import com.codrim.cs.data.server.subservice.TimeZoneSubService;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.time.DateUtils;

import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.Resource;

/**
 * @author Liang.Zhuge on 17/08/2017.
 */
@Service(version = OfferDataService.RPC_VERSION)
public class OfferDataServiceImpl implements OfferDataService {
    @Resource StatCsAdvOfferMapper dayStatCsAdvOfferMapper;
    @Resource RealTimeDataDao realTimeDataDao;
    @Resource TimeZoneSubService timeZoneSubService;
    @Resource StatCsAdvOfferMapper advOfferMapper;

    @Override
    public List<OfferDataDTO> offerData(OfferDataParamDTO param) {
        List<OfferDataDO> offerDataDOs = dayStatCsAdvOfferMapper.offerDatas(OfferDataParam.of(param),
                timeZoneSubService.prefixTableNameForTimeZone(param.getTimeZone()));

        if (CollectionUtils.isEmpty(offerDataDOs)) {
            return null;
        }

        final Date startDate = DateUtils.truncate(param.getStartDay(), Calendar.DAY_OF_MONTH);
        final Date endDay = DateUtils.addDays(DateUtils.truncate(param.getEndDay(), Calendar.DAY_OF_MONTH), 1);

        final List<RealTimeGroupByField> fields = new ArrayList<>();
        fields.add(RealTimeGroupByField.Offer);

        return offerDataDOs.stream()
                .map(offerData -> mergeRealTimeData(startDate.toInstant(), endDay.toInstant(), fields, offerData))
                .collect(Collectors.toList());
    }

    @Override
    public PageResult<StatementOfferDTO> findStatementAdvOfferByParam(Map param, int zoneId) {
        Integer page= Integer.parseInt(Optional.ofNullable(String.valueOf(param.get("page"))).filter(o -> NumberUtils.isNumber(o)).orElse("0"));
        Integer rows= Integer.parseInt(Optional.ofNullable(String.valueOf(param.get("rows"))).filter(o -> NumberUtils.isNumber(o)).orElse("10"));
        Integer start = 0;
        if(page>0){
            start=(page - 1) * rows;
        }
        if(rows<=0){
            rows=10;
        }
        param.put("start",start);
        param.put("end", rows);

        Optional<String> optional=Optional.ofNullable(String.valueOf(param.get("dataType")));
        String value=optional.filter(num->NumberUtils.isNumber(num)).orElse("1");
        Integer dataType=Integer.parseInt(value);
        if(dataType==0){
            dataType=1;
        }
        int billType=1;
        Object billTypeObj=param.get("billType");
        if(billTypeObj==null){
            billType=1;
        }else{
            billType=Integer.parseInt(String.valueOf(Optional.ofNullable(billTypeObj).filter(o -> NumberUtils.isNumber(String.valueOf(o))).orElse("1")));
        }
        List<StatementOfferDTO> dayStatCsAdvOfferDOS=null;
        Integer total=0;
        boolean isDownLoad = Boolean.valueOf(String.valueOf(Optional.ofNullable(param.get("isDownLoad")).orElse(false)));
        //下载导出渠道分配结算数
        if (isDownLoad) {
            String offerIdStr = String.valueOf(param.get("offerIds"));
            String timeZoneListStr = String.valueOf(param.get("offerTimeZoneList"));
            String[] offerIdStrArr = offerIdStr.split(",");
            String[] timeZoneStrArr = timeZoneListStr.split(",");
            List<Integer> offerIds = Arrays.asList(offerIdStrArr).stream().map(i -> {
                return Integer.parseInt(i);
            }).collect(Collectors.toList());
            List<Integer> timeZoneList = Arrays.asList(timeZoneStrArr).stream().map(i -> {
                return Integer.parseInt(i);
            }).collect(Collectors.toList());

            if (offerIds.size() == timeZoneList.size()) {
                dayStatCsAdvOfferDOS = new ArrayList<>();
                for (int i = 0; i < timeZoneList.size(); i++) {
                    Integer timeZone = timeZoneList.get(i);
                    Integer offerId = offerIds.get(i);
                    List<StatementOfferDTO> offerList;
                    param.put("offerIds", Arrays.asList(offerId));
                    if (timeZone != 1000) {
                        //查找对接的广告,获取要对接的渠道
                        offerList = advOfferMapper.findAdvOfferByParam(param, timeZoneSubService.prefixTableNameForTimeZone(timeZone));
                    } else {
                        offerList = advOfferMapper.findAdvOfferManualByParam(param);
                    }

                    //去重
                    Set<String> offTimeZoneList = new HashSet<>();
                    for (int j = 0; j < offerList.size(); j++) {
                        StatementOfferDTO statementOfferDTO = offerList.get(j);
                        offTimeZoneList.add(statementOfferDTO.getOfferId() + "_" + statementOfferDTO.getAffiliateId());
                    }
                    List<Integer> affList = new ArrayList<>();
                    for (String s : offTimeZoneList) {
                        String off[] = s.split("_");
                        String affId = off[1];
                        affList.add(Integer.parseInt(affId));
                    }

                    if (timeZone != 1000) {
                        //查询所有渠道的对接广告的数据
                        for (Integer affId : affList) {
                            Map queryParam = new HashMap();
                            queryParam.put("offerIds", Arrays.asList(offerId));
                            queryParam.put("affiliateId", affId);
                            queryParam.put("advertiserId", param.get("advertiserId"));
                            queryParam.put("startTime", param.get("startTime"));
                            queryParam.put("endTime", param.get("endTime"));
                            queryParam.put("isDownLoad", true);
                            queryParam.put("start", start);
                            queryParam.put("end", rows);
                            List<StatementOfferDTO> advdayStatCsAdvOfferList = advOfferMapper.findAdvOfferByParam(queryParam, timeZoneSubService.prefixTableNameForTimeZone(timeZone));
                            if (advdayStatCsAdvOfferList != null && advdayStatCsAdvOfferList.size() > 0) {
                                dayStatCsAdvOfferDOS.addAll(advdayStatCsAdvOfferList);
                            }
                        }
                    }

                    //查找不对接广告,获取不对接广告的渠道
                    //查询所有渠道的对接广告的数据
                    for (Integer affId : affList) {
                        Map queryParam = new HashMap();
                        queryParam.put("offerIds", Arrays.asList(offerId));
                        queryParam.put("affiliateId", affId);
                        queryParam.put("advertiserId", param.get("advertiserId"));
                        queryParam.put("startTime", param.get("startTime"));
                        queryParam.put("endTime", param.get("endTime"));
                        queryParam.put("isDownLoad", true);
                        queryParam.put("start", start);
                        queryParam.put("end", rows);
                        List<StatementOfferDTO> advdayStatCsAdvOfferList = advOfferMapper.findAdvOfferManualByParam(queryParam);
                        if (advdayStatCsAdvOfferList != null && advdayStatCsAdvOfferList.size() > 0) {
                            dayStatCsAdvOfferDOS.addAll(advdayStatCsAdvOfferList);
                        }
                    }
                }
            }
        } else {
            if (dataType == 1) {
                dayStatCsAdvOfferDOS = advOfferMapper.findAdvOfferByParam(param, timeZoneSubService.prefixTableNameForTimeZone(zoneId));
                total = advOfferMapper.findAdvOfferByParamCount(param, timeZoneSubService.prefixTableNameForTimeZone(zoneId));
            } else if (dataType == 2) {
                dayStatCsAdvOfferDOS = advOfferMapper.findAdvOfferManualByParam(param);
                total = advOfferMapper.findAdvOfferManualByParamCount(param);
            }
        }
        HashMap<Integer, Integer> offerIdTimes = new HashMap<>();
        if(dayStatCsAdvOfferDOS!=null&&dayStatCsAdvOfferDOS.size()>0){
            for(StatementOfferDTO statementOfferDTO:dayStatCsAdvOfferDOS){
                if(statementOfferDTO!=null){
                    Integer offerIdTime = offerIdTimes.get(statementOfferDTO.getOfferId());
                    if (offerIdTime != null) {
                        offerIdTimes.put(statementOfferDTO.getOfferId(), offerIdTime + 1);
                    } else {
                        offerIdTimes.put(statementOfferDTO.getOfferId(), 1);
                    }
                    if(statementOfferDTO.getOfferIdSdates()!=null){
                        String offersdate=statementOfferDTO.getOfferIdSdates();
                        String[] offersArr=offersdate.split(",");
                        String dateList="";
                        for(String str:offersArr){
                            String[] data=str.split("_");
                            String sDate=data[1];
                            if(StringUtils.isEmpty(dateList)){
                                dateList=sDate;
                            }else {
                                dateList+=","+sDate;
                            }
                            break;
                        }
                        statementOfferDTO.setSdateList(dateList);
                    }
                    statementOfferDTO.setAprice(statementOfferDTO.getSingleAccessPrice());
                    statementOfferDTO.setPprice(statementOfferDTO.getSinglePutPrice());
                    statementOfferDTO.setConversion(billType==1?statementOfferDTO.getGc():statementOfferDTO.getConversion());

                    //日期区间显示
                    String sdateL = statementOfferDTO.getSdateList();
                    sdateL = sdateL.replaceAll("-", "");
                    if (!StringUtils.isEmpty(sdateL) && sdateL.length() == 8) {
                        String startTime = String.valueOf(param.get("startTime"));
                        String endTime = String.valueOf(param.get("endTime"));
                        String startTimeStr = startTime.substring(0, 4) + "-" + startTime.substring(4, 6);
                        String endTimeStr = endTime.substring(0, 4) + "-" + endTime.substring(4, 6);
                        String dateStr = sdateL.substring(0, 4) + "-" + sdateL.substring(4, 6);
                        String startDateS = getFirstDayOfMonth(dateStr);
                        if (startTimeStr.equals(dateStr)) {
                            startDateS = dateStr + "-" + sdateL.substring(6, 8);
                        }
                        String endDateS = getLastDayOfMonth(dateStr);
                        if (dateStr.equals(endTimeStr)) {
                            endDateS = endTimeStr + "-" + endTime.substring(6, 8);
                        }
                        statementOfferDTO.setDateSection(startDateS + "~" + endDateS);
                    }
                }
            }
        }
        for (int i = 0; i < dayStatCsAdvOfferDOS.size(); i++) {
            StatementOfferDTO statementOfferDTO = dayStatCsAdvOfferDOS.get(i);
            if (null == statementOfferDTO) {
                continue;
            }
            if (offerIdTimes.get(statementOfferDTO.getOfferId()) > 1) {
                String sdateL = statementOfferDTO.getSdateList();
                sdateL = sdateL.replaceAll("-", "");
                String dateStr = sdateL.substring(0, 4) + "-" + sdateL.substring(4, 6);
                statementOfferDTO.setOfferName("(" + dateStr + ")");
                dayStatCsAdvOfferDOS.set(i, statementOfferDTO);
            }
        }
        PageResult<StatementOfferDTO> pageResult = new PageResult<>();
        pageResult.setTotal(total);
        pageResult.setRows(dayStatCsAdvOfferDOS);
        return pageResult;
    }

    @Override
    public List<StatementOfferDTO> findAdvOfferManualByParam(BillCsOfferParam param) {
        return advOfferMapper.findAdvOfferManualByMapParam(param);
    }

    private OfferDataDTO mergeRealTimeData(Instant startDate, Instant endDay,
                                           List<RealTimeGroupByField> fields, OfferDataDO offerData) {
        OfferDataDTO dto = offerData.toOfferDataDTO();

        final RealTimeDataSearchParam realTimeParam = new RealTimeDataSearchParam();
        realTimeParam.setOfferId(offerData.getOfferId());
        List<RealTimeData> realTimeDatas = realTimeDataDao
                .mergeRealTimeData(realTimeDataDao.allRedisRealTimeData(), fields, realTimeParam, startDate, endDay);

        Optional.ofNullable(realTimeDatas).ifPresent(list -> list.forEach(item -> item.addToOfferReportData(dto,null)));

        return dto;
    }


    public static String getFirstDayOfMonth(String datestr) {
        if (StringUtils.isBlank(datestr)) return null;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = strToDateNotDD(datestr);
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
        LocalDateTime endOfDay = localDateTime.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
        Date dates = Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());
        return sdf.format(dates);
    }

    /**
     * java8(别的版本获取2月有bug) 获取某月最后一天的23:59:59
     */
    public static String getLastDayOfMonth(String datestr) {
        if (StringUtils.isBlank(datestr)) return null;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = strToDateNotDD(datestr);
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
        LocalDateTime endOfDay = localDateTime.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX);
        Date dates = Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());
        return sdf.format(dates);
    }

    /**
     * 将短时间格式字符串转换为时间 yyyy-MM( 2017-02)
     */
    public static Date strToDateNotDD(String strDate) {
        if (StringUtils.isBlank(strDate)) return null;
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM");
        ParsePosition pos = new ParsePosition(0);
        Date strtodate = formatter.parse(strDate, pos);
        return strtodate;
    }

}
